from typing import Optional
from fastapi import APIRouter, HTTPException, Depends
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from config import bn, db
from app import users
from method import Bn
from method import Log
import pandas as pd
import requests
import h5py
import os
import json
import time

from decimal import Decimal, getcontext

router = APIRouter(default_response_class=JSONResponse)

class Kline(BaseModel):
    symbol: Optional[str] = ''
    interval: Optional[str] = ''
    startTime: Optional[int] = None
    endTime: Optional[int] = None
    limit: Optional[int] = 10

@router.post('/kline')
def binance_klines(kline: Kline):
    params = {
        'symbol': kline.symbol,
        'interval': kline.interval,
        'limit': kline.limit
    }
    if kline.startTime:
        params['startTime'] = kline.startTime
    if kline.endTime:
        params['endTime'] = kline.endTime

    response = requests.get(bn.klines, params=params)
    data = response.json()

    # 将数据转换为DataFrame
    df = pd.DataFrame(data, columns=[
        "OpenTime", "Open", "High", "Low", "Close", "Volume",
        "CloseTime", "QuoteVolume", "Trades", "TakerBuyBaseVolume",
        "TakerBuyQuoteVolume", "Ignore"
    ])
    df = df.drop(columns=["Ignore", "Trades", "QuoteVolume", "TakerBuyBaseVolume", "TakerBuyQuoteVolume"])
    # 转换时间戳为日期时间格式
    df['OpenTime'] = pd.to_datetime(df['OpenTime'], unit='ms').dt.tz_localize("UTC").dt.tz_convert("Asia/Shanghai")
    df['CloseTime'] = pd.to_datetime(df['CloseTime'], unit='ms').dt.tz_localize("UTC").dt.tz_convert("Asia/Shanghai")

    # 将DataFrame转换为JSON格式
    result = df.to_dict(orient='records')
    return result

@router.get('/exchangeInfo/update')
async def update_exchangeInfo():
    data = []
    keys = 'symbols'
    response = requests.get(bn.exchangeInfo)
    data = response.json()
    # 过滤所有 USDT 交易对
    data = [s for s in data["symbols"] if s["quoteAsset"] == "USDT"]
    # 判断币种交割日期是否已经到期
    data = [s for s in data if s["deliveryDate"] > (int(time.time() * 1000) - 60 * 60 * 1000)]
    data = [{k: d[k] for k in ['baseAsset', 'quoteAsset', 'symbol', 'deliveryDate', 'onboardDate', 'filters']} for d in data]
    with h5py.File(db.exchange_info, 'w') as f:
        # 序列化为 JSON 字符串
        json_str = json.dumps(data)
        f.create_dataset(
            f'{keys}',
            data=json_str,
        )
    return data

@router.get('/exchangeInfo')
async def binance_exchangeInfo():
    data = []
    keys = 'symbols'
    if os.path.exists(db.exchange_info):
        # 读取数据文件（'r' 表示只读）
        with h5py.File(db.exchange_info, 'r') as f:
            if keys in f:
                # 读取嵌套组中的数据集
                data_list = f[keys][()]
                # 把JSON字符串反序列化回对象
                data = json.loads(data_list.decode('utf-8'))
    
    if len(data) == 0:
        data = await update_exchangeInfo()
    return data

@router.get('/ticker/24hr')
def binance_exchangeInfo(symbol: str = ''):
    params = {}
    if symbol:
        params = {
            'symbol': symbol
        }
    response = requests.get(bn.ticker24hr, params=params)
    data = response.json()
    return data

@router.get('/client/account')
def binance_exchangeInfo(user: users.User = Depends(users.get_current_user)):
    try:
        if user:
            my_binance = Bn.Binance(user.username)
            getcontext().prec = 10
            # 获取合约账户信息
            account_info = my_binance.synced(bn.account)
            assets = [s for s in account_info['assets'] if s['asset'] == 'USDT']
            positions_info = my_binance.synced(bn.positionRisk)
            positions = [s for s in positions_info if Decimal(s['initialMargin']) != Decimal('0')]
            return {
                'assets': assets,
                'positions': positions
            }
    except Exception as e:        
        raise HTTPException(status_code=400, detail=str(e))

class BinanceOrder(BaseModel):
    symbol: Optional[str] = ''
    side: Optional[str] = ''
    type: Optional[str] = '' 
    price: Optional[float] = None
    quantity: Optional[float] = None
    positionSide: Optional[str] = '' 
    closePosition: Optional[bool] = False
    timeInForce: Optional[str] = ''
    workingType: Optional[str] = ''
    stopPrice: Optional[float] = None  

@router.post('/order')
def binance_order(params: BinanceOrder, user: users.User = Depends(users.get_current_user)):
    try:
        if user:
            params_info = {
                'symbol': params.symbol,
                'side': params.side,
                'type': 'MARKET',
            }
            if params.price:
                params_info['price'] = params.price
            if params.type:
                params_info['type'] = params.type
            if params.workingType:
                params_info['workingType'] = params.workingType    
            if params.timeInForce:
                params_info['timeInForce'] = params.timeInForce
            if params.positionSide:
                params_info['positionSide'] = params.positionSide
            if params.stopPrice:
                params_info['stopPrice'] = params.stopPrice
            if params.closePosition:
                params_info['closePosition'] = params.closePosition
            else:
                params_info['quantity'] = params.quantity
            Log.set_log(f'{params_info}', 'order_params')
            my_binance = Bn.Binance(user.username)
            # 获取合约账户信息
            order = my_binance.synced(bn.order, params_info, 'post')
            return order
    except Exception as e:
        Log.set_log(f'binance_order 下单报错: {e}', 'error')        
        raise HTTPException(status_code=400, detail=str(e))
    
class BinanceKey(BaseModel):
    binance_key: Optional[str] = ''
    binance_secret: Optional[str] = ''

@router.post("/apikey")
async def get_user_binance(Key: BinanceKey, user: users.User = Depends(users.get_current_user)):
    try:
        my_binance = Bn.Binance(user.username, Key)
        my_binance.synced(bn.account)
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))
    try:
        data = users.get_user_data(user.username)
        if data:
            await users.del_user(user.username)
            with h5py.File(db.user_data, 'a') as f:
                data['binance_key'] = Key.binance_key
                data['binance_secret'] = Key.binance_secret
                # 把数据转成json字符串
                json_str = json.dumps(data)
                f.create_dataset(
                    user.username,
                    data=json_str,
                    dtype=h5py.string_dtype()
                )
        return {"message": "API keys updated successfully"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
